/**********
    @name: editor组件
    @describtion: props: title:字段别名 ,value: 字段值
    @author:liubingye
    @date:2023-02-10 18:36:37
***********/
<template>
  <div class="tinymce-box">
    <div class="editor-header">
      <h2>{{modelTitle}}</h2>
    </div>
    <el-form-item :rules="editorRule" :prop="editorName"></el-form-item>
    <Editor :id="editorName" v-model="content" :init="init" tag-name="div" />
    <ImageUpload v-model:showDialog="showAxupImgs" :limit="20" @getImage="insertImage" :isToJpg="true"></ImageUpload>
  </div>
</template>

<script>
//引入tinymce编辑器
import Editor from '@tinymce/tinymce-vue'

//引入node_modules里的tinymce相关文件文件
import tinymce from 'tinymce/tinymce' //tinymce默认hidden，不引入则不显示编辑器
import 'tinymce/themes/silver' //编辑器主题，不引入则报错
import 'tinymce/icons/default' //引入编辑器图标icon，不引入则不显示对应图标
import 'tinymce/plugins/advlist' //高级列表
import 'tinymce/plugins/anchor' //锚点
import 'tinymce/plugins/autolink' //自动链接
import 'tinymce/plugins/autoresize' //编辑器高度自适应,注：plugins里引入此插件时，Init里设置的height将失效
import 'tinymce/plugins/autosave' //自动存稿
import 'tinymce/plugins/charmap' //特殊字符
import 'tinymce/plugins/code' //编辑源码
import 'tinymce/plugins/codesample' //代码示例
import 'tinymce/plugins/directionality' //文字方向
import 'tinymce/plugins/emoticons' //表情
import 'tinymce/plugins/fullpage' //文档属性
import 'tinymce/plugins/fullscreen' //全屏
import 'tinymce/plugins/help' //帮助
import 'tinymce/plugins/hr' //水平分割线
import 'tinymce/plugins/image' //插入编辑图片
import 'tinymce/plugins/importcss' //引入css
import 'tinymce/plugins/insertdatetime' //插入日期时间
import 'tinymce/plugins/link' //超链接
import 'tinymce/plugins/lists' //列表插件
import 'tinymce/plugins/media' //插入编辑媒体
import 'tinymce/plugins/nonbreaking' //插入不间断空格
import 'tinymce/plugins/pagebreak' //插入分页符
import 'tinymce/plugins/paste' //粘贴插件
import 'tinymce/plugins/preview' //预览
import 'tinymce/plugins/print' //打印
import 'tinymce/plugins/quickbars' //快速工具栏
import 'tinymce/plugins/save' //保存
import 'tinymce/plugins/searchreplace' //查找替换
import 'tinymce/plugins/tabfocus' //切入切出，按tab键切出编辑器，切入页面其他输入框中
import 'tinymce/plugins/table' //表格
import 'tinymce/plugins/template' //内容模板
import 'tinymce/plugins/textcolor' //文字颜色
import 'tinymce/plugins/textpattern' //快速排版
import 'tinymce/plugins/toc' //目录生成器
import 'tinymce/plugins/visualblocks' //显示元素范围
import 'tinymce/plugins/visualchars' //显示不可见字符
import 'tinymce/plugins/wordcount' //字数统计
import '@npkg/tinymce-plugins/importword' //三方插件导入word
import '@npkg/tinymce-plugins/indent2em'

import { watch, ref, onMounted, computed } from 'vue'
import { useStore } from 'vuex'
import { convertHexToBase64, parseRtf, transBase64FromImage } from '@/utils/tools'
import { singleUpload } from '@/utils/upload'

export default {
  name: 'TEditor',
  components: {
    Editor,
  },
  props: {
    title: {
      type: String,
      default: '',
    },
    modelValue: {
      type: String,
      default: '',
    },
    editorId: {
      type: String,
      default: 'myedit',
    },
    isDestroy: {
      type: Boolean,
      default: false,
    },
    field: {
      type: String,
      default: '',
    },
    required: {
      type: Boolean,
      default: false,
    },
  },
  emits: { 'update:modelValue': null },
  setup(props, context) {
    const setAvatarBase64 = (src, width, height) => {
      return new Promise((resolve) => {
        let image = new Image()
        // 处理缓存
        image.src = src + '?v=' + Math.random()
        // 支持跨域图片
        image.crossOrigin = '*'
        if (width) image.width = width
        if (height) image.height = height
        image.onload = () => {
          let base64 = transBase64FromImage(image)
          resolve(base64)
        }
      })
    }
    const store = useStore()
    const init = {
      language_url: process.env.BASE_URL + 'tinymce/langs/zh_CN.js', //引入语言包文件
      language: 'zh_CN', //语言类型

      skin_url: process.env.BASE_URL + 'tinymce/skins/ui/oxide', //皮肤：浅色

      plugins:
        'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave ', //插件配置
      toolbar: [
        'importword axupimgs media link table | code undo redo | formatselect fontselect fontsizeselect',
        'lineheight bullist numlist | forecolor backcolor bold italic underline strikethrough | alignleft aligncenter alignright alignjustify outdent indent indent2em | blockquote subscript superscript',
      ], //工具栏配置，设为false则隐藏
      menubar: false, //菜单栏配置，设为false则隐藏，不配置则默认显示全部菜单，也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
      fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px', //字体大小
      font_formats:
        '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;', //字体样式
      lineheight_formats: '12px 14px 16px 20px 24px 26px 30px 32px 34px 36px', //行高配置，也可配置成"12px 14px 16px 20px"这种形式

      height: 400, //注：引入autoresize插件时，此属性失效
      placeholder: '在这里输入文字',
      branding: false, //tiny技术支持信息是否显示
      resize: false, //编辑器宽高是否可变，false-否,true-高可变，'both'-宽高均可，注意引号
      elementpath: false, //元素路径是否显示

      content_css: process.env.BASE_URL + 'tinymce/tinycontent.css',
      content_style: 'img {max-width:100%;}', //直接自定义可编辑区域的css样式
      paste_data_images: true, //图片是否可粘贴
      convert_urls: false,
      // eslint-disable-next-line no-unused-vars
      images_upload_handler: (blobInfo, success, failure, progress) => {
        // 方法1：用base64的图片形式上传图片
        // const img = 'data:image/jpeg;base64,' + blobInfo.base64()
        // success(img)

        // 方法2：上传oos
        let data = new FormData()
        data.append('file', blobInfo.blob())
        // 获取图片文件的宽高属性
        data.append('startX', 0)
        data.append('startY', 0)
        data.append('path', 'content')
        data.append('type', 0)
        const imageUrl = URL.createObjectURL(blobInfo.blob())
        const img = new Image()
        img.src = imageUrl
        img.onload = function () {
          const width = img.width
          const height = img.height
          URL.revokeObjectURL(imageUrl)
          data.append('cropWidth', width)
          data.append('cropHeight', height)
          data.append('scaledWidth', width)
          data.append('scaledHeight', height)
        }
        singleUpload(data, store.state.content.singleActionUrl).then((res) => {
          if (res.code === 20000) {
            success(res.data.url)
          }
        })
      },
      init_instance_callback: function (editor) {
        editor.execCommand('selectAll')
        editor.selection.getRng().collapse(false)
        editor.focus()

        editor.on('paste', (evt) => {
          const clipboardData = evt.clipboardData
          const isImage = clipboardData.types.length && clipboardData.types.join('').includes('Files')
          if (!isImage) {
            console.log('元素粘贴')
            let rtfData = evt.clipboardData.getData('text/rtf')
            console.log('rtfData', rtfData)
            let htmlData = evt.clipboardData.getData('text/html')
            console.log('htmlData', htmlData)
            //------------------------粘贴word核心代码开始-------------------------
            const hexStrings = parseRtf(rtfData)
            console.log('evt', evt)
            console.log('hexStrings', hexStrings)
            // 获取base64图片数据
            const base64Images = hexStrings.map((hexObj) => {
              let convertHexToBase64Str = convertHexToBase64(hexObj.hex)
              console.log('convertHexToBase64Str', convertHexToBase64Str)
              return convertHexToBase64Str
            })
            setTimeout(() => {
              const wordImages = tinymce.activeEditor.dom.doc.querySelectorAll('img[src*="file://"]')
              const urlImages = tinymce.activeEditor.dom.doc.querySelectorAll('img[src^="http"]')
              console.log('wordImages', wordImages)
              console.log('urlImages', urlImages)
              urlImages.forEach((item) => {
                setAvatarBase64(item.src).then((base64) => {
                  console.log('base64', base64)
                  item.src = base64
                  tinymce.activeEditor.uploadImages()
                })
              })
              wordImages.forEach((item, index) => {
                console.log('item', item)
                console.log('index', index)
                console.log('hexStrings[index].type', hexStrings[index]?.type)
                console.log('base64Images[index]', base64Images[index])

                item.src = `data:${hexStrings[index]?.type || 'image/png'};base64,${base64Images[index]}`
                tinymce.activeEditor.uploadImages()
              })
            }, 200)
            //------------------------粘贴word核心代码结束-------------------------
            return
          }
          const file = clipboardData.files[0]
          if (
            !file ||
            !file.name ||
            !(
              file.name.toLowerCase().indexOf('.png') !== -1 ||
              file.name.toLowerCase().indexOf('.gif') !== -1 ||
              file.name.toLowerCase().indexOf('.jpeg') !== -1 ||
              file.name.toLowerCase().indexOf('.jpg') !== -1
            )
          ) {
            this.$message.error('您粘贴的不是图片请检查！')
            return
          }
          if (file.size / 1024 / 1024 > 5) {
            this.$message.error('上传失败，图片大小请控制在 5M 以内')
            return
          }
        })
      },

      // eslint-disable-next-line no-unused-vars
      urlconverter_callback: (url, node, onSave, name) => {
        if (node === 'img' && url.startsWith('blob:')) {
          tinymce.activeEditor && tinymce.activeEditor.uploadImages()
        }
        return url
      },
      paste_postprocess: function (plugin, args) {
        if (process.env.NODE_ENV === 'development') console.log(args)
        args.content = 'helloworld'
      },

      setup: (editor) => {
        editor.ui.registry.addButton('axupimgs', {
          text: `<i class="iconfont">&#xe609;</i>`,
          tooltip: '批量上传',
          onAction: () => {
            showAxupImgs.value = true
          },
        })
      },
    }
    tinymce.init
    const editorRule = ref([])
    const validateEdit = (rule, value, callback) => {
      if (value === '') {
        callback(new Error(props.title + '不能为空'))
      } else {
        callback()
      }
    }
    const editorName = ref(props.editorId)
    const content = computed({
      get: () => props.modelValue,
      set: (val) => {
        context.emit('update:modelValue', val)
      },
    })
    const modelTitle = ref(props.title)
    watch(
      () => props.isDestroy,
      () => {
        tinymce.editors[editorName.value].destroy()
      }
    )
    const showAxupImgs = ref(false)
    const insertImage = (imgList) => {
      let imgContent = ``
      imgList.forEach((item) => {
        let _img = `<p><img src="${item.url}" /></p>`
        imgContent = imgContent + _img
      })
      tinymce.editors[editorName.value].insertContent(imgContent + '<p></p>')
    }
    onMounted(() => {
      if (props.required) {
        editorRule.value.push({ validator: validateEdit, trigger: 'change' })
      }
    })
    return {
      content,
      modelTitle,
      init,
      editorName,

      showAxupImgs,
      insertImage,
      editorRule,
    }
  },
}
</script>

<style lang="scss" scoped>
.tinymce-box {
  width: 100%;
  .editor-header {
    height: 60px;
    line-height: 60px;
    h2 {
      font-size: 18px;
      color: #333333;
    }
  }
  ::v-deep(.el-form-item) {
    margin: 0;
  }
  ::v-deep(.el-form-item__content) {
    margin-left: 0 !important;
    .el-form-item__error {
      top: -14px;
    }
  }
}
::v-deep(.axupimg-box .el-dialog__body) {
  padding: 0;
}
.axupimg-box {
  .inner-axupimg-box {
    display: flex;
    height: 450px;
    .axupimg-upload-box {
      width: 520px;
      height: 100%;
      .local-upload {
        padding: 10px;
        width: 500px;
        .local-upload-list {
          height: 330px;
          display: flex;
          flex-wrap: wrap;
          position: relative;
          align-content: flex-start;
          & > div {
            height: 110px;
            width: 110px;
            margin-right: 10px;
            margin-bottom: 10px;
            background-color: #f0f2f7;
          }
          li {
            height: 110px;
            width: 110px;
            box-sizing: border-box;
            list-style: none;
            border: 1px solid #dcdfe6;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            border-radius: 5px;
            cursor: pointer;
            .img-box {
              height: 108px;
              width: 108px;
              display: flex;
              justify-content: center;
              align-items: center;
              img {
                max-width: 108px;
                max-height: 108px;
              }
            }
            .progress-box {
              width: 100px;
              position: absolute;
              bottom: 5px;
            }
            .remove-upload {
              color: $placeholderColor;
              position: absolute;
              right: 5px;
              top: 8px;
              cursor: pointer;
              display: none;
            }
            .choose-check {
              position: absolute;
              left: 5px;
              top: 0;
            }
            &:hover {
              .remove-upload {
                display: block;
              }
            }
            &.is-choose {
              border-color: $mainColor;
            }
          }
        }
      }
      .online-upload {
        padding: 10px;
        width: 500px;
        .online-upload-list {
          display: flex;
          flex-wrap: wrap;
          height: 375px;
          .online-upload-item {
            height: 115px;
            width: 115px;
            border-radius: 6px;
            background-color: $borderColor;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-right: 10px;
            margin-bottom: 10px;
            cursor: pointer;
            box-sizing: border-box;
            img {
              max-width: 100%;
              max-height: 100%;
            }
            &:nth-child(4n) {
              margin-right: 0;
            }
            &.is-choose {
              border: 1px solid $mainColor;
            }
          }
        }
      }
    }
    .axupimg-list-box {
      width: 180px;
      height: 100%;
      border-left: 1px solid #dcdfe6;
      box-sizing: border-box;
      padding: 10px;
      p {
        margin-bottom: 10px;
      }
      .chose-img-list {
        height: 400px;
        justify-content: center;
        flex-direction: column;
        .chose-img-box {
          height: 130px;
          width: 145px;
          display: flex;
          align-items: center;
          justify-content: center;
          background-color: #f0f2f7;
          margin-bottom: 10px;
          border-radius: 6px;
          img {
            max-height: 100%;
            max-width: 100%;
          }
        }
      }
    }
  }
}
</style>
